package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Component
@Aspect
@Slf4j
public class AutoFillAspect {
    @Before("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")  //扫描mapper 包和注解@AutoFill
    public void before(JoinPoint joinPoint) throws Exception {
        log.info("开始公共字段填充");

        //1.获取原始方法上的注解 AutoFill 对象，目的是区分insert或update操作
        //1.1 获取原始方法前面对象（AOP提供的签名对象）
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

        //1.2 获取原始方法上的注解
        AutoFill autoFill = methodSignature.getMethod().getAnnotation(AutoFill.class);

        //1.3 获取里面的操作类型对象
        OperationType operationType = autoFill.value();

        //2.获取到原始方法参数对象
        Object[] objects = joinPoint.getArgs();
        // 安全判断：不能为空
        if(objects == null || objects.length == 0){
            log.info("当前方法无公共字段");
            return;
        }
        // 获取第一个参数对象
        Object object = objects[0];
        Class<?> clazz = object.getClass();
        //3.对参数对象进行填充
        //3.0 准备填充的数据
        Long empId = BaseContext.getCurrentId();    //当前登录用户id
        LocalDateTime now = LocalDateTime.now();    //当前时间
        //3.1 填充修改人和修改时间
        // 使用反射获取object对象里面公共字段的set方法
        // 语法：clazz.getMethod(方法名。方法参数字节码对象...)
        //更新时间的set方法
        Method setUpdateTimeMethod = clazz.getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
        //更新人的set方法
        Method setUpdateUserMethod = clazz.getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
        // 反射指定方法填充数据，语法：method.invoke(所属对象，参数值...）
        // 非反射方式：所属对象.set方法（参数值）
        setUpdateTimeMethod.invoke(object, now);
        setUpdateUserMethod.invoke(object, empId);

        //填充数据
        //3.2 如果是insert操作，获取到当前登录用户的id，填充到创建人、创建时间、更新人、更新时间字段
        if(operationType == OperationType.INSERT){
            //创建时间的set方法
            Method setCreateTimeMethod = clazz.getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
            //创建人的set方法
            Method setCreateUserMethod = clazz.getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
            //调用set方法填充数据
            setCreateTimeMethod.invoke(object, now);
            setCreateUserMethod.invoke(object, empId);
            setUpdateTimeMethod.invoke(object, now);
            setUpdateUserMethod.invoke(object, empId);

            log.info("公共字段填充完毕");
        }


    }
}
